from abc import ABC, abstractmethod
from langchain_core.documents import Document
import typing as T
from io import BytesIO
from pathlib import Path
import pandas as pd
from ...exception import InvalidBlobType


class IFileLoader(ABC):
    uuid: str = None

    def verify(self, blob: T.Union[str, Path, bytes, BytesIO]):
        if isinstance(blob, str):
            blob = Path(blob).as_posix()
        elif isinstance(blob, Path):
            blob = blob.as_posix()
        elif isinstance(blob, BytesIO):
            pass
        elif isinstance(blob, bytes):
            blob = BytesIO(blob)
        else:
            raise InvalidBlobType(type(blob))
        return blob

    @abstractmethod
    def load(
        self,
        blob: T.Union[str, Path, bytes, BytesIO],
        uuid: str,
        file_name: str = None,
        **kwargs,
    ) -> T.List[Document]: ...

    def _process_table_data(
        self,
        df: pd.DataFrame,
        file_name: str,
        sheet_name: str = None,
        file_type: str = "csv",
        row_size: int = 15,
    ) -> T.List[Document]:
        docs = []
        columns_list = list(df.columns)
        aggregated_data = {}
        for col in columns_list:
            aggregated_data[col] = df[col].tolist()
        for start in range(0, df.shape[0], row_size):
            end = start + row_size
            if end > df.shape[0]:
                end = df.shape[0]

            row_text = "\n".join(
                f"{col}: {str(aggregated_data[col][start:end])}" for col in columns_list
            )
            metadata = {
                "file_name": file_name,
                "uuid": self.uuid,
                "total_rows": df.shape[0],
                "columns": columns_list,
                "type": file_type,
            }

            if sheet_name is not None:
                metadata["sheet_name"] = sheet_name
            docs.append(
                Document(
                    page_content=row_text,
                    metadata=metadata,
                )
            )

        return docs

    def setUuid(self, uuid: str):
        self.uuid = uuid
